1 /*
2  * Hunt - a framework for web and console application based on Collie using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd
5  *
6  * Developer: HuntLabs
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.routing.routegroup;
13 
14 import hunt.routing.define;
15 import hunt.routing.route;
16 
17 import std.algorithm.searching;
18 import std.string;
19 
20 class RouteInfo
21 {
22 	string mca;
23 	string path;
24 	HTTP_METHODS[] methods;
25 
26 	this(string mca,string path,HTTP_METHODS[] methods)
27 	{
28 		this.mca = mca;
29 		this.path = path;
30 		this.methods = methods;
31 	}
32 }
33 
34 class RoutePathInfo
35 {
36 	string path;
37 	HTTP_METHODS[] methods;
38 
39 	this(string path,HTTP_METHODS[] methods)
40 	{
41 		this.path = path;
42 		this.methods = methods;
43 	}
44 }
45 
46 class RouteRegInfo
47 {
48 	HTTP_METHODS[] methods;
49 	this(HTTP_METHODS[] methods)
50 	{
51 		this.methods = methods;
52 	}
53 }
54 
55 class RouteGroup
56 {
57     this(string name = DEFAULT_ROUTE_GROUP)
58     {
59         this._name = name;
60     }
61 
62     public
63     {
64         void setName(string name)
65         {
66             this._name = name;
67         }
68 
69         string getName()
70         {
71             return this._name;
72         }
73 
74         RouteGroup addRoute(Route route)
75         {
76             if (route.getRegular())
77             {
78                 this._regexRoutes ~= route;
79             }
80             else
81             {
82 				//path 
83                 this._routes[new RoutePathInfo(route.getPattern(),route.getMethods)] = route;
84             }
85 
86             string mca = ((route.getModule()) ? route.getModule() ~ "." : "") ~ route.getController() ~ "." ~ route.getAction();
87 
88             this._mcaRoutes[new RouteInfo(mca,route.getPattern,route.getMethods)] = route;
89 
90             return this;
91         }
92 
93         Route getRoute(string method,string mca)
94         {
95 			auto m = getMethod(method);
96 			foreach(k,v;_mcaRoutes){
97 				if(k.mca == mca){
98 					if(canFind(k.methods,m) || k.methods == [HTTP_METHODS.ALL])
99 						return v;
100 				}
101 			}
102 			return null;
103         }
104 
105         Route match(string method,string path)
106         {
107             // TODO: 引用类型使用结构体二次包装
108             Route route = null;
109 
110 			auto http_method = getMethod(toUpper(method));
111 			foreach(k,v;_routes){
112 				if(k.path == path){
113 					if(canFind(k.methods,http_method) || k.methods == [HTTP_METHODS.ALL])
114 						route = v;
115 				}
116 			}
117 
118             if (route)
119             {
120                 return route.copy();
121             }
122             else
123             {
124             	foreach(key, value; this._routes)
125             	{
126 					import std.string;
127 					import std.algorithm.searching;
128             		if (startsWith(path,key.path) && value.staticFilePath.length > 0 && 
129 							(canFind(key.methods,http_method) || key.methods == [HTTP_METHODS.ALL]))
130             		{
131             				return value;
132             		}
133             	}
134             }
135             
136             import std.regex;
137             import std.uri : decode;
138 
139             foreach (r; this._regexRoutes)
140             {
141                 auto matched = path.match(regex(r.getPattern()));
142 				bool matchMethod = false;
143 				if(canFind(r.getMethods,http_method) || r.getMethods == [HTTP_METHODS.ALL])
144 					matchMethod = true;
145                 if (matched && matchMethod)
146                 {
147                     route = r.copy();
148 
149                     string[string] params;
150 
151                     foreach(i, key; route.getParamKeys())
152                     {
153                         params[key] = decode(matched.captures[i + 1]);
154                     }
155 
156                     route.setParams(params);
157 
158                     return route;
159                 }
160             }
161 
162             return null;
163         }
164     }
165 
166     private
167     {
168         string _name;
169         Route[RoutePathInfo] _routes;
170         Route[RouteInfo] _mcaRoutes;
171         Route[] _regexRoutes;
172     }
173 }